from django.db import models
from django.utils import timezone
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
import json

User = get_user_model()


class NotificationTemplate(models.Model):
    """
    通知模板模型
    """
    TEMPLATE_TYPES = [
        ('email', '邮件'),
        ('sms', '短信'),
        ('push', '推送'),
        ('in_app', '应用内'),
        ('wechat', '微信'),
    ]
    
    CATEGORY_CHOICES = [
        ('system', '系统通知'),
        ('risk', '风险预警'),
        ('portfolio', '投资组合'),
        ('market', '市场资讯'),
        ('transaction', '交易通知'),
        ('account', '账户通知'),
    ]
    
    name = models.CharField(max_length=100, verbose_name='模板名称')
    template_type = models.CharField(max_length=20, choices=TEMPLATE_TYPES, verbose_name='模板类型')
    category = models.CharField(max_length=20, choices=CATEGORY_CHOICES, verbose_name='通知类别')
    subject_template = models.CharField(max_length=200, verbose_name='主题模板', blank=True)
    content_template = models.TextField(verbose_name='内容模板')
    variables = models.JSONField(default=dict, verbose_name='模板变量', help_text='模板中可用的变量列表')
    is_active = models.BooleanField(default=True, verbose_name='是否启用')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        db_table = 'notification_template'
        verbose_name = '通知模板'
        verbose_name_plural = '通知模板'
        unique_together = ['name', 'template_type']
    
    def __str__(self):
        return f"{self.name} ({self.get_template_type_display()})"
    
    def render_content(self, context):
        """
        渲染模板内容
        """
        try:
            from django.template import Template, Context
            template = Template(self.content_template)
            return template.render(Context(context))
        except Exception as e:
            return f"模板渲染错误: {str(e)}"
    
    def render_subject(self, context):
        """
        渲染主题
        """
        if not self.subject_template:
            return ''
        try:
            from django.template import Template, Context
            template = Template(self.subject_template)
            return template.render(Context(context))
        except Exception as e:
            return f"主题渲染错误: {str(e)}"


class Notification(models.Model):
    """
    通知记录模型
    """
    STATUS_CHOICES = [
        ('pending', '待发送'),
        ('sent', '已发送'),
        ('delivered', '已送达'),
        ('read', '已读'),
        ('failed', '发送失败'),
        ('cancelled', '已取消'),
    ]
    
    PRIORITY_CHOICES = [
        ('low', '低'),
        ('normal', '普通'),
        ('high', '高'),
        ('urgent', '紧急'),
    ]
    
    recipient = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='接收者')
    template = models.ForeignKey(NotificationTemplate, on_delete=models.CASCADE, verbose_name='通知模板')
    subject = models.CharField(max_length=200, verbose_name='主题')
    content = models.TextField(verbose_name='内容')
    priority = models.CharField(max_length=10, choices=PRIORITY_CHOICES, default='normal', verbose_name='优先级')
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending', verbose_name='状态')
    
    # 关联对象（通用外键）
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True)
    object_id = models.PositiveIntegerField(null=True, blank=True)
    related_object = GenericForeignKey('content_type', 'object_id')
    
    # 发送相关字段
    scheduled_time = models.DateTimeField(null=True, blank=True, verbose_name='计划发送时间')
    sent_time = models.DateTimeField(null=True, blank=True, verbose_name='发送时间')
    delivered_time = models.DateTimeField(null=True, blank=True, verbose_name='送达时间')
    read_time = models.DateTimeField(null=True, blank=True, verbose_name='阅读时间')
    
    # 错误信息
    error_message = models.TextField(blank=True, verbose_name='错误信息')
    retry_count = models.IntegerField(default=0, verbose_name='重试次数')
    max_retries = models.IntegerField(default=3, verbose_name='最大重试次数')
    
    # 额外数据
    metadata = models.JSONField(default=dict, verbose_name='元数据')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        db_table = 'notification'
        verbose_name = '通知记录'
        verbose_name_plural = '通知记录'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['recipient', 'status']),
            models.Index(fields=['status', 'scheduled_time']),
            models.Index(fields=['template', 'created_at']),
        ]
    
    def __str__(self):
        return f"{self.subject} - {self.recipient.username}"
    
    def mark_as_sent(self):
        """
        标记为已发送
        """
        self.status = 'sent'
        self.sent_time = timezone.now()
        self.save(update_fields=['status', 'sent_time', 'updated_at'])
    
    def mark_as_delivered(self):
        """
        标记为已送达
        """
        self.status = 'delivered'
        self.delivered_time = timezone.now()
        self.save(update_fields=['status', 'delivered_time', 'updated_at'])
    
    def mark_as_read(self):
        """
        标记为已读
        """
        self.status = 'read'
        self.read_time = timezone.now()
        self.save(update_fields=['status', 'read_time', 'updated_at'])
    
    def mark_as_failed(self, error_message):
        """
        标记为发送失败
        """
        self.status = 'failed'
        self.error_message = error_message
        self.retry_count += 1
        self.save(update_fields=['status', 'error_message', 'retry_count', 'updated_at'])
    
    def can_retry(self):
        """
        是否可以重试
        """
        return self.retry_count < self.max_retries and self.status == 'failed'


class NotificationPreference(models.Model):
    """
    用户通知偏好设置
    """
    user = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name='用户')
    
    # 各类通知的开关
    email_enabled = models.BooleanField(default=True, verbose_name='邮件通知')
    sms_enabled = models.BooleanField(default=True, verbose_name='短信通知')
    push_enabled = models.BooleanField(default=True, verbose_name='推送通知')
    in_app_enabled = models.BooleanField(default=True, verbose_name='应用内通知')
    wechat_enabled = models.BooleanField(default=False, verbose_name='微信通知')
    
    # 通知类别偏好
    system_notifications = models.BooleanField(default=True, verbose_name='系统通知')
    risk_notifications = models.BooleanField(default=True, verbose_name='风险预警')
    portfolio_notifications = models.BooleanField(default=True, verbose_name='投资组合通知')
    market_notifications = models.BooleanField(default=False, verbose_name='市场资讯')
    transaction_notifications = models.BooleanField(default=True, verbose_name='交易通知')
    account_notifications = models.BooleanField(default=True, verbose_name='账户通知')
    
    # 免打扰时间
    quiet_hours_enabled = models.BooleanField(default=False, verbose_name='免打扰时间')
    quiet_start_time = models.TimeField(null=True, blank=True, verbose_name='免打扰开始时间')
    quiet_end_time = models.TimeField(null=True, blank=True, verbose_name='免打扰结束时间')
    
    # 频率限制
    max_daily_notifications = models.IntegerField(default=50, verbose_name='每日最大通知数')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        db_table = 'notification_preference'
        verbose_name = '通知偏好'
        verbose_name_plural = '通知偏好'
    
    def __str__(self):
        return f"{self.user.username}的通知偏好"
    
    def is_notification_allowed(self, notification_type, category):
        """
        检查是否允许发送通知
        """
        # 检查通知类型开关
        type_enabled = getattr(self, f"{notification_type}_enabled", False)
        if not type_enabled:
            return False
        
        # 检查通知类别开关
        category_enabled = getattr(self, f"{category}_notifications", False)
        if not category_enabled:
            return False
        
        # 检查免打扰时间
        if self.quiet_hours_enabled and self.is_in_quiet_hours():
            return False
        
        # 检查每日通知数量限制
        if self.has_reached_daily_limit():
            return False
        
        return True
    
    def is_in_quiet_hours(self):
        """
        检查是否在免打扰时间内
        """
        if not self.quiet_hours_enabled or not self.quiet_start_time or not self.quiet_end_time:
            return False
        
        current_time = timezone.now().time()
        
        if self.quiet_start_time <= self.quiet_end_time:
            # 同一天内的时间段
            return self.quiet_start_time <= current_time <= self.quiet_end_time
        else:
            # 跨天的时间段
            return current_time >= self.quiet_start_time or current_time <= self.quiet_end_time
    
    def has_reached_daily_limit(self):
        """
        检查是否达到每日通知限制
        """
        today = timezone.now().date()
        daily_count = Notification.objects.filter(
            recipient=self.user,
            created_at__date=today
        ).count()
        
        return daily_count >= self.max_daily_notifications


class NotificationChannel(models.Model):
    """
    通知渠道配置
    """
    CHANNEL_TYPES = [
        ('email', '邮件'),
        ('sms', '短信'),
        ('push', '推送'),
        ('wechat', '微信'),
        ('webhook', 'Webhook'),
    ]
    
    name = models.CharField(max_length=50, verbose_name='渠道名称')
    channel_type = models.CharField(max_length=20, choices=CHANNEL_TYPES, verbose_name='渠道类型')
    config = models.JSONField(default=dict, verbose_name='渠道配置')
    is_active = models.BooleanField(default=True, verbose_name='是否启用')
    priority = models.IntegerField(default=0, verbose_name='优先级')
    
    # 限流配置
    rate_limit_per_minute = models.IntegerField(default=60, verbose_name='每分钟限制')
    rate_limit_per_hour = models.IntegerField(default=1000, verbose_name='每小时限制')
    rate_limit_per_day = models.IntegerField(default=10000, verbose_name='每日限制')
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        db_table = 'notification_channel'
        verbose_name = '通知渠道'
        verbose_name_plural = '通知渠道'
        unique_together = ['name', 'channel_type']
    
    def __str__(self):
        return f"{self.name} ({self.get_channel_type_display()})"


class NotificationLog(models.Model):
    """
    通知发送日志
    """
    notification = models.ForeignKey(Notification, on_delete=models.CASCADE, verbose_name='通知')
    channel = models.ForeignKey(NotificationChannel, on_delete=models.CASCADE, verbose_name='发送渠道')
    
    # 发送结果
    success = models.BooleanField(verbose_name='是否成功')
    response_code = models.CharField(max_length=20, blank=True, verbose_name='响应代码')
    response_message = models.TextField(blank=True, verbose_name='响应消息')
    
    # 发送详情
    sent_at = models.DateTimeField(auto_now_add=True, verbose_name='发送时间')
    duration_ms = models.IntegerField(null=True, blank=True, verbose_name='发送耗时(毫秒)')
    
    # 额外信息
    metadata = models.JSONField(default=dict, verbose_name='元数据')
    
    class Meta:
        db_table = 'notification_log'
        verbose_name = '通知日志'
        verbose_name_plural = '通知日志'
        ordering = ['-sent_at']
        indexes = [
            models.Index(fields=['notification', 'sent_at']),
            models.Index(fields=['channel', 'success']),
        ]
    
    def __str__(self):
        status = '成功' if self.success else '失败'
        return f"{self.notification.subject} - {self.channel.name} - {status}"